use anyhow::Result;
use std::{io, net::SocketAddr};
use tokio::{io::AsyncWriteExt, net::TcpListener};
use tracing::{info, warn};

const BUF_SIZE: usize = 4096;

#[tokio::main]
async fn main() -> Result<()>{

    let addr = "0.0.0.0:6379";
    let listener = TcpListener::bind(addr).await?;
    println!("Dredis: listening on: {}", addr);

    loop {
        let (stream, addr) = listener.accept().await?;
        println!("Accepted connection from: {}", addr);
        tokio::spawn(async move{
           if let Err(e) = process_redis_conn(stream,addr).await {
               println!("Error processing conn with {}: {:?}", addr, e.to_string());
           }
        });
    }
    Ok(())
}

async  fn process_redis_conn(mut stream: tokio::net::TcpStream, raddr: SocketAddr) ->Result<()> {
    loop {
        stream.readable().await?;
        let mut buf = Vec::with_capacity(BUF_SIZE);

        match stream.try_read_buf(&mut  buf) {
            Ok(0) => break,
            Ok(n) => {
                println!("read {} bytes", n);
                let line = String::from_utf8_lossy(&buf);
                println!("{:?}", line);
                stream.write_all(b"+OK\r\n").await?;
            },
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                continue;
            },
            Err(e) => {
                return Err(e.into());
            }
        }

    }
    warn!("Connection {} closed", raddr);
    Ok(())
}